/*
 * Copyright (C) 2012 DataSymphony (http://datasymphony.com.au)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package au.com.ds.restty;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.PropertyConfigurator;

import au.com.ds.restty.exc.InvalidTemplate;
import au.com.ds.restty.js.JavaScriptEngine;
import au.com.ds.restty.js.JsAnyObject;
import au.com.ds.restty.js.JsObject;
import au.com.ds.restty.js.JsString;
import au.com.ds.restty.util.Utils;

public class Config {
	public static class ContextObjectMetadata {
		private String mClassName;
		private JsObject mSettings;
		
		private ContextObjectMetadata(String className, JsObject settings) {
			this.mClassName = className;
			this.mSettings = settings;
		}

		public String getClassName() {
			return mClassName;
		}

		public JsObject getSettings() {
			return mSettings;
		}
	}
	
	private static final String WORK_DIR = "work";
	private static final String LOG4J_CONFIG = "config/log4j.properties";
	private static final String CONFIG_FILE_FORMAT = "config/profiles/%s/_config.js";
	private static final String TEMPLATES_DIR_FORMAT = "config/profiles/%s";
	private Map<String, ContextObjectMetadata> mContextObjectInfo;
	private String mTemplatesDir;
	
	protected Config(String profileName) {
		PropertyConfigurator.configure(LOG4J_CONFIG);
		
		mContextObjectInfo = new HashMap<String, ContextObjectMetadata>();
		
		String script;
		File file;
		try {
			mTemplatesDir = String.format(TEMPLATES_DIR_FORMAT, profileName);
			file = new File(String.format(CONFIG_FILE_FORMAT, profileName));
			script = Utils.getScript(file);			
		} catch (Exception e){
			throw new InvalidTemplate("Error reading config file for: " + profileName, e);
		}
		
		try {
			JsObject config = JavaScriptEngine.getInstance().execute(script, file.getName()).as(JsObject.class);
			if (config == null) {
				throw new InvalidTemplate("Top-level structure must be a JavaScript object");
			}
						
			JsObject contextObjects = config.get("contextObjects").as(JsObject.class);
			if (contextObjects == null) {
				throw new InvalidTemplate("[contextObjects] structure must be a JavaScript Object");
			}
			
			for (Map.Entry<JsAnyObject, JsAnyObject> item : contextObjects.getValue().entrySet()) {
				JsString coName = item.getKey().as(JsString.class);
				if (coName == null) {
					throw new InvalidTemplate("[contextObjects[i].name] value must be a String");
				}
				
				JsString className = item.getValue().as(JsString.class);
				JsObject settings = null;
				if (className == null) {
					JsObject complexMetadata = item.getValue().as(JsObject.class);
					if (complexMetadata == null) {
						throw new InvalidTemplate("[contextObjects[i].value] structure must be a String or Object");
					}
					
					className = complexMetadata.get("implementation").as(JsString.class); 
					if (className == null) {
						throw new InvalidTemplate("[contextObjects[i].value.implementation] value must be a String");
					}
					
					settings = complexMetadata.get("settings").as(JsObject.class);
				}
				
				ContextObjectMetadata metadata = new ContextObjectMetadata(className.getValue(), settings);
				mContextObjectInfo.put(coName.getValue(), metadata);
			}			
		} catch (Exception e){
			throw new InvalidTemplate("Error processing config file: " + file.getPath(), e);			
		}
	}
	
	public Map<String, ContextObjectMetadata> getContextObjectsMetadata() {
		return mContextObjectInfo;
	}

	public String getTemplatesDir() {
		return mTemplatesDir;
	}

	public String getWorkDir() {
		return WORK_DIR;
	}
	
	
}
